﻿using System.Text;

using RabbitMQ.Client;

namespace RabbitMQSample.WebApi.RabbitMQLibs
{
    public abstract class RabbitMQShareProducerBase : IRabbitMQShareProducerBase, IDisposable
    {
        private readonly IRabbitMQConnectionFactory _rabbitMQConnectionFactory;
        private readonly ILogger _logger;
        protected IModel _channel = null;

        public RabbitMQShareProducerBase(IRabbitMQConnectionFactory rabbitMQConnectionFactory, ILogger logger)
        {
            _rabbitMQConnectionFactory = rabbitMQConnectionFactory;
            _logger = logger;
        }

        public virtual void Dispose()
        {
            _channel?.Dispose();
        }

        /// <summary>
        /// 发布消息（带消息确认）
        /// </summary>
        /// <param name="routingKey">路由key，当使用默认交换机或交换机类型为 Direct 时，默认可以与队列名保持一致</param>
        /// <param name="msg">消息</param>
        /// <param name="exchange">交换机</param>
        /// <param name="stoppingToken"></param>
        /// <returns>返回消息是否发送到 RabbitMQ</returns>
        public virtual async Task<bool> ProduceWithConfirmAsync(string routingKey, string msg, string exchange = "", CancellationToken stoppingToken = default)
        {
            if (_channel == null || _channel.IsClosed)
            {
                _channel?.Dispose();
                _channel = await _rabbitMQConnectionFactory.GetShareChannelAsync(ChannelTypeEnum.Write, stoppingToken);
            }

            if (_channel == null) return false; // 连接失败

            int maxRetry = 3;
        Retry:
            if (stoppingToken.IsCancellationRequested) return false;
            _channel.ConfirmSelect();

            var body = Encoding.UTF8.GetBytes(msg);
            var basicProperties = _channel.CreateBasicProperties(); // 配置消息持久化
            basicProperties.Persistent = true;
            basicProperties.DeliveryMode = 2;
            _channel.BasicPublish(exchange: exchange, routingKey: routingKey, basicProperties: basicProperties, body: body);

            try
            {
                if (_channel.WaitForConfirms(TimeSpan.FromSeconds(5), out bool timedOut) == false || timedOut)
                {
                    if (--maxRetry <= 0) return false;
                    goto Retry;
                }

                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 发布消息
        /// </summary>
        /// <param name="routingKey">路由key，当使用默认交换机或交换机类型为 Direct 时，默认可以与队列名保持一致</param>
        /// <param name="msg">消息</param>
        /// <param name="exchange">交换机</param>
        /// <param name="stoppingToken"></param>
        public virtual async Task<bool> ProduceAsync(string routingKey, string msg, string exchange = "", CancellationToken stoppingToken = default)
        {
            if (_channel == null || _channel.IsClosed)
            {
                _channel?.Dispose();
                _channel = await _rabbitMQConnectionFactory.GetShareChannelAsync(ChannelTypeEnum.Write, stoppingToken);
            }

            if (_channel == null) return false; // 连接失败

            var body = Encoding.UTF8.GetBytes(msg);
            var basicProperties = _channel.CreateBasicProperties(); // 配置消息持久化
            basicProperties.Persistent = true;
            basicProperties.DeliveryMode = 2;

            _channel.BasicPublish(exchange: exchange, routingKey: routingKey, basicProperties: basicProperties, body: body);

            return true;
        }
    }
}
